package com.javaziliao.design.service;

import cn.hutool.core.collection.CollUtil;
import com.javaziliao.design.items.composite.AbstractProductItem;
import com.javaziliao.design.items.composite.ProductComposite;
import com.javaziliao.design.items.vistor.AddItemVistor;
import com.javaziliao.design.items.vistor.DelItemVistor;
import com.javaziliao.design.pojo.ProductItem;
import com.javaziliao.design.repo.ProductItemRepository;
import com.javaziliao.design.utils.RedisCommonProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Transactional
public class ProductItemService {
    @Autowired
    private RedisCommonProcessor redisProcessor;
    @Autowired
    private ProductItemRepository productItemRepository;
    @Autowired
    private AddItemVistor addItemVistor;
    @Autowired
    private DelItemVistor delItemVistor;

    public ProductComposite addItems(ProductItem productItem){
        productItemRepository.addItem(productItem.getName(), productItem.getPid());
        ProductComposite addItem = ProductComposite.builder()
                .id(productItemRepository.findByNameAndPid(productItem.getName(),productItem.getPid()).getId())
                .name(productItem.getName())
                .pid(productItem.getPid())
                .child(new ArrayList<>())
                .build();
        AbstractProductItem updateItems = addItemVistor.vistor(addItem);
        redisProcessor.set("items",updateItems);
        return (ProductComposite) updateItems;
    }

    public ProductComposite delItems(ProductItem item){
        productItemRepository.delItem(item.getId());
        ProductComposite delItem = ProductComposite.builder()
                .id(item.getId())
                .name(item.getName())
                .pid(item.getPid())
                .build();
        AbstractProductItem updateItems = delItemVistor.vistor(delItem);
        redisProcessor.set("items",updateItems);
        return (ProductComposite) updateItems;
    }

    public ProductComposite fetchAllItems() {
        Object cacheItems = redisProcessor.get("items");
        if (cacheItems != null) {
            return (ProductComposite) cacheItems;
        }
        List<ProductItem> fetchDbItems = productItemRepository.findAll();
        if (CollUtil.isEmpty(fetchDbItems)) {
            return null;
        }
        ProductComposite items = generateProductTree(fetchDbItems);
        if (items == null) {
            return null;
        }
        redisProcessor.set("items", items);
        return items;
    }

    private ProductComposite generateProductTree(List<ProductItem> fetchDbItems) {
        List<ProductComposite> composites = new ArrayList<>(fetchDbItems.size());
        fetchDbItems.forEach(dbItem -> composites.add(
                ProductComposite.builder()
                        .id(dbItem.getId())
                        .pid(dbItem.getPid())
                        .name(dbItem.getName())
                        .build()
        ));
        Map<Integer, List<ProductComposite>> groupingList = composites.stream().collect(Collectors.groupingBy(ProductComposite::getPid));
        composites.forEach(item -> {
            List<ProductComposite> list = groupingList.get(item.getId());
            item.setChild(CollUtil.isEmpty(list) ? new ArrayList<>() : list.stream().collect(Collectors.toList()));
        });
        return composites.size() == 0 ? null : composites.get(0);
    }
}
